/* @flow */

import config from '../config';
import { initUse } from './use';
import { initMixin } from './mixin';
import { initExtend } from './extend';
import { initAssetRegisters } from './assets';
import { set, del } from '../observer/index';
import { ASSET_TYPES } from 'shared/constants';
import builtInComponents from '../components/index';
import { observe } from 'core/observer/index';

import {
  warn,
  extend,
  nextTick,
  mergeOptions,
  defineReactive
} from '../util/index';

/* 初始化构造器的api */
export function initGlobalAPI(Vue: GlobalAPI) {
  const configDef = {};
  configDef.get = () => config;
  if (process.env.NODE_ENV !== 'production') {
    configDef.set = () => {
      // 并且不能给 config 赋值，可以修改其属性
      // Vue.config = {} 这样是不可取的
      warn(
        'Do not replace the Vue.config object, set individual fields instead.'
      );
    };
  }
  // 通过 Vue.config 拿到配置信息 定义了configDef的get属性
  Object.defineProperty(Vue, 'config', configDef);

  // 工具类不作为公共暴露的API使用
  Vue.util = {
    warn,
    extend,
    mergeOptions,
    defineReactive
  };

  // Vue.set = Vue.prototype.$set
  Vue.set = set;

  // Vue.delete = Vue.prototype.$delete
  Vue.delete = del;

  // Vue.nextTick = Vue.prototype.$nextTick
  Vue.nextTick = nextTick;

  // 2.6 explicit observable API
  // 2.6 新增 api，可以把传入数据包装成响应式数据
  // 可以做一个为小型的vuex来使用
  Vue.observable = <T>(obj: T): T => {
    observe(obj);
    return obj;
  };

  // 构造函数的默认选项默认为 component ,directive ,filter
  Vue.options = Object.create(null);
  ASSET_TYPES.forEach(type => {
    Vue.options[type + 's'] = Object.create(null);
  });

  // options里的_base属性存储Vue构造器
  Vue.options._base = Vue;

  /**
   * vue\src\shared\util.js extend
   * extend 方法实现了对象的合并，如果属性相同，则用新的属性值覆盖旧值。
   * 这里实现了内置组件的合并  vue\src\core\components\index.js
   * 内置 KeepAlive 组件 builtInComponents
   * 内置组件和全局组件合并
   */
  extend(Vue.options.components, builtInComponents);

  // Vue.use()
  initUse(Vue);

  //  Vue.mixin()
  initMixin(Vue);

  // Vue.extend()定义extend扩展子类构造器的方法
  initExtend(Vue);

  // Vue.components, Vue.directive, Vue.filter;
  initAssetRegisters(Vue);
}

// Vue.options = {
//   components: {
//     KeepAlive: {}
//     Transition: {}
//     TransitionGroup: {}
//   },
//   directives: {
//     model: {inserted: ƒ, componentUpdated: ƒ}
//     show: {bind: ƒ, update: ƒ, unbind: ƒ}
//   },
//   filters: {}
//   _base
// }
